﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Windows;
using System.Windows.Media.Animation;
using System.IO;

using SlimDX;

using LibSnesDotNet;
using LibSnesDotNet.Core;
using LibSnesDotNet.Audio;
using LibSnesDotNet.Video;
using LibSnesDotNet.Input;

using Size = System.Drawing.Size;

namespace LibSnesDotNet.UI
{
	public class MainForm : HybridForm
	{
		readonly Vector2 _aspect = Vector2.Normalize(new Vector2(4.0F, 3.0F));

		Configuration _config;

		CoreDriver _coreDriver;
		IVideoDriver _videoDriver;
		IAudioDriver _audioDriver;
		bool _inFullscreenMode;
		bool _isClosed;

		public MainForm(Configuration config)
			: base(new UIWindow(config))
		{
			_config = config;

			Text = "libsnes.NET";
			MaximizeBox = false;
			BackColor = Color.Black;

			_inFullscreenMode = false;
			UIWindow.KeyDown += (s, e) =>
			{
				if (e.Key == System.Windows.Input.Key.Escape)
				{
					if (_inFullscreenMode)
					{
						Focus();
						UIWindow.Visibility = Visibility.Hidden;
						_videoDriver.IsFullscreen = true;
					}
				}
			};

			_isClosed = false;
		}

		UIWindow UIWindow { get { return (UIWindow)Overlay; } }
		internal CoreDriver CoreDriver { get { return _coreDriver; } }

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);

			WindowElement windowConfig = _config.UI.Window;
			if (windowConfig.X.HasValue && windowConfig.Y.HasValue)
			{
				Rectangle configRect = new Rectangle(windowConfig.X.Value, windowConfig.Y.Value, windowConfig.Width, windowConfig.Height);
				if (Screen.GetWorkingArea(configRect).IntersectsWith(configRect))
				{
					Left = configRect.X;
					Top = configRect.Y;
				}
			}

			ClientSize = new Size(windowConfig.Width, windowConfig.Height);

			_coreDriver = new CoreDriver((UIWindow)Overlay, _config);

			_videoDriver = new Direct3D11Driver(this, null);
			_audioDriver = new XAudio2Driver(null);

			_coreDriver.SetDrivers(_videoDriver, _audioDriver);
			_coreDriver.InputAggregator.AddDriver(new RawInputDriver(this));
		}

		protected override void CoerceClientSize(ref Size newSize)
		{
			if (!_inFullscreenMode)
			{
				var v = new Vector2(newSize.Width, newSize.Height);
				v = Vector2.Multiply(_aspect, Vector2.Dot(_aspect, v));
				newSize.Width = (int)Math.Round(v.X);
				newSize.Height = (int)Math.Round(v.Y);

				newSize.Width = newSize.Width < 597 ? 597 : newSize.Width;
				newSize.Height = newSize.Height < 448 ? 448 : newSize.Height;
			}
		}

		protected override void OnKeyDown(KeyEventArgs e)
		{
			WindowElement windowConfig = _config.UI.Window;

			if (e.KeyCode == Keys.Enter && e.Modifiers == Keys.Alt)
			{
				if (!_inFullscreenMode)
				{
					_inFullscreenMode = true;

					windowConfig.X = Left;
					windowConfig.Y = Top;
					windowConfig.Width = ClientSize.Width;
					windowConfig.Height = ClientSize.Height;

					UIWindow.Topmost = true;
					TopMost = true;
					FormBorderStyle = FormBorderStyle.None;
					WindowState = FormWindowState.Maximized;

					UIWindow.Visibility = Visibility.Hidden;
					_videoDriver.IsFullscreen = true;
				}
				else
				{
					_videoDriver.IsFullscreen = false;
					UIWindow.Visibility = Visibility.Visible;

					FormBorderStyle = FormBorderStyle.Sizable;
					WindowState = FormWindowState.Normal;
					UIWindow.Topmost = false;
					TopMost = false;

					Left = windowConfig.X.Value;
					Top = windowConfig.Y.Value;
					ClientSize = new Size(windowConfig.Width, windowConfig.Height);

					_inFullscreenMode = false;
				}
			}
			else if (e.KeyCode == Keys.Escape)
			{
				if (_inFullscreenMode)
				{
					if (_videoDriver.IsFullscreen)
					{
						_videoDriver.IsFullscreen = false;
						UIWindow.Visibility = Visibility.Visible;
						UIWindow.Focus();
					}
				}
			}

			base.OnKeyDown(e);
		}

		protected override void OnAppDeactivated(EventArgs e)
		{
			WindowElement windowConfig = _config.UI.Window;

			if (_inFullscreenMode && !_isClosed)
			{
				_videoDriver.IsFullscreen = false;
				UIWindow.Visibility = Visibility.Visible;

				FormBorderStyle = FormBorderStyle.Sizable;
				WindowState = FormWindowState.Normal;
				UIWindow.Topmost = false;
				TopMost = false;

				Left = windowConfig.X.Value;
				Top = windowConfig.Y.Value;
				ClientSize = new Size(windowConfig.Width, windowConfig.Height);

				_inFullscreenMode = false;

				WindowState = FormWindowState.Minimized;
			}

			base.OnAppDeactivated(e);
		}

		protected override void OnClosed(EventArgs e)
		{
			WindowElement windowConfig = _config.UI.Window;

			_isClosed = true;

			UIWindow.Close();

			if (!_inFullscreenMode)
			{
				windowConfig.X = Left;
				windowConfig.Y = Top;
				windowConfig.Width = ClientSize.Width;
				windowConfig.Height = ClientSize.Height;
			}

			if (_coreDriver != null)
			{
				_coreDriver.Stop();
				_coreDriver.InputAggregator.DisposeAllDrivers();
				_coreDriver.Dispose();
			}

			if (_videoDriver != null) { _videoDriver.Dispose(); }
			if (_audioDriver != null) { _audioDriver.Dispose(); }

			base.OnClosed(e);
		}

	}
}
